package com.tjetc.common.handlers;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tjetc.dao.TagsMapper;
import com.tjetc.entity.Tag;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 处理景点标签字段的 TypeHandler
 * 实现数据库中 JSON 格式标签 ID 列表与 Java List<Tag> 对象的相互转换
 * 通过 MyBatis 的 BaseTypeHandler 扩展实现自定义类型转换
 */
@Component
public class SpotTagsTypeHandler extends BaseTypeHandler<List<Tag>> {

    /**
     * ObjectMapper 实例，用于 JSON 和 Java 对象的相互转换
     * 定义为静态常量以便重用，避免重复创建实例
     */
    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 标签数据访问对象，用于根据标签 ID 查询完整的标签信息
     * 由于 TypeHandler 不在 Spring 容器中，需要静态引用
     */
    private static TagsMapper tagsMapper;

    /**
     * 设置标签映射器的静态方法
     * 由于 TypeHandler 不是 Spring 管理的 Bean，无法使用自动注入
     * 需要通过外部设置 tagsMapper 实例
     *
     * @param tagsMapper 标签数据访问对象
     */
    public static void setTagsMapper(TagsMapper tagsMapper) {
        SpotTagsTypeHandler.tagsMapper = tagsMapper;
    }

    /**
     * 将 Java 对象设置到 PreparedStatement 中（写入数据库）
     * 将 List<Tag> 对象转换为 JSON 字符串存储到数据库
     *
     * @param ps PreparedStatement 对象
     * @param i 参数位置索引
     * @param parameter 标签列表参数
     * @param jdbcType JDBC 类型
     * @throws SQLException SQL 异常
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List<Tag> parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, toJson(parameter));
    }

    /**
     * 通过列名从 ResultSet 中获取值并转换为 Java 类型
     * 从数据库中读取 JSON 字符串并转换为 List<Tag> 对象
     *
     * @param rs 结果集
     * @param columnName 列名
     * @return 转换后的标签列表
     * @throws SQLException SQL 异常
     */
    @Override
    public List<Tag> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return toTagNames(toList(rs.getString(columnName)));
    }

    /**
     * 通过列索引从 ResultSet 中获取值并转换为 Java 类型
     *
     * @param rs 结果集
     * @param columnIndex 列索引
     * @return 转换后的标签列表
     * @throws SQLException SQL 异常
     */
    @Override
    public List<Tag> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return toTagNames(toList(rs.getString(columnIndex)));
    }

    /**
     * 从 CallableStatement 中获取值并转换为 Java 类型
     * 用于存储过程的输出参数
     *
     * @param cs CallableStatement 对象
     * @param columnIndex 列索引
     * @return 转换后的标签列表
     * @throws SQLException SQL 异常
     */
    @Override
    public List<Tag> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return toTagNames(toList(cs.getString(columnIndex)));
    }

    /**
     * 将 JSON 字符串转换为标签 ID 列表
     *
     * @param json 数据库中存储的 JSON 格式标签 ID 字符串
     * @return 标签 ID 列表
     */
    private List<Integer> toList(String json) {
        try {
            // 打印数据库中读取的 JSON 字符串，用于调试
            System.out.println("JSON String: " + json);

            // 使用 Jackson 将 JSON 转换为 List<Integer> 类型
            List<Integer> tagIds = objectMapper.readValue(json, new TypeReference<List<Integer>>() {});
            System.out.println("Converted tag IDs: " + tagIds);

            return tagIds;
        } catch (Exception e) {
            throw new RuntimeException("Error converting JSON string to list", e);
        }
    }

    /**
     * 根据标签 ID 列表查询完整的标签对象列表
     *
     * @param tagIds 标签 ID 列表
     * @return 完整的标签对象列表
     */
    private List<Tag> toTagNames(List<Integer> tagIds) {
        // 如果映射器未初始化或者标签 ID 列表为空，返回空列表
        if (tagsMapper == null || tagIds == null || tagIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 通过数据访问对象查询完整的标签信息
        List<Tag> tags = tagsMapper.selectTagsByIds(tagIds);

        // 打印查询到的标签信息，用于调试
        tags.forEach(tag -> System.out.println("Found tag: " + tag.getTagName()));

        return tags;
    }

    /**
     * 将标签列表转换为 JSON 字符串
     *
     * @param list 标签对象列表
     * @return JSON 格式的字符串
     */
    private String toJson(List<Tag> list) {
        try {
            return objectMapper.writeValueAsString(list);
        } catch (Exception e) {
            throw new RuntimeException("Error converting list to JSON string", e);
        }
    }
}